//
// Created by zhu on 25-7-27.
//
#include <gtest/gtest.h>

#include "../material/HandleInput.h"
#include "test_const.h"

TEST(ch2, exercise0201) {
    // {
    //     //C++: Arithmetic Types
    //     std::cout << "bool size: " << sizeof(bool) << std::endl;
    //     std::cout << "char size: " << sizeof(char) << std::endl;
    //     std::cout << "wchar_t size: " << sizeof(wchar_t) << std::endl;
    //     std::cout << "char16_t size: " << sizeof(char16_t) << std::endl;
    //     std::cout << "char32_t size: " << sizeof(char32_t) << std::endl;
    //     std::cout << "short size: " << sizeof(short) << std::endl;
    //     std::cout << "int size: " << sizeof(int) << std::endl;
    //     std::cout << "long size: " << sizeof(long) << std::endl;
    //     std::cout << "long long size: " << sizeof(long long) << std::endl;
    //     std::cout << "float size: " << sizeof(float) << std::endl;
    //     std::cout << "double size: " << sizeof(double) << std::endl;
    //     std::cout << "long double size: " << sizeof(long double) << std::endl;
    //     /**
    //     *bool size: 1
    //     char size: 1
    //     wchar_t size: 2
    //     char16_t size: 2
    //     char32_t size: 4
    //     short size: 2
    //     int size: 4
    //     long size: 4
    //     long long size: 8
    //     float size: 4
    //     double size: 8
    //     long double size: 16
    //     char is signed*/
    //
    // }
    //
    // {
    //     //char 通常是 signed char
    //     if (char(-1) < 0)
    //         std::cout << "char is signed\n";
    //     else
    //         std::cout << "char is unsigned\n";
    // }
    //
    // {
    //     bool b = 42; // b is true
    //     int i = b; // i has value 1
    //     i = 3.14; // i has value 3
    //     double pi = i; // pi has value 3.0
    //     unsigned char c = -1; // assuming 8-bit chars, c has value 255
    //     signed char c2 = 256; // assuming 8-bit chars, the value of c2 is undefined
    //
    //     std::cout << b << std::endl;
    //     std::cout << i << std::endl;
    //     std::cout << pi << std::endl;
    //     std::cout << (unsigned int)(c) << std::endl;//255对应的char超出了ASCII的范围
    //     std::cout << c2 << std::endl;
    // }
    //
    // {
    //     //unsigned int + (signed) int
    //     unsigned u = 10;
    //     int i = -42;
    //     std::cout << i + i << std::endl;//-84
    //     std::cout << u + i << std::endl;//4294967264 = 2^32 - 42 + 10
    // }
    // {
    //     //怎么用unsigned打印倒数10 - 0
    //     unsigned u = 11;
    //     while (u > 0) {
    //         --u;
    //         std::cout << u << std::endl;
    //     }
    //
    //
    //     for (unsigned i = 11; i > 0;) {
    //         std::cout << --i << std::endl;
    //     }
    // }
    //
    // {
    //     // multiline string literal
    //     std::cout << "a really, really long string literal "
    //     "that spans two lines" << std::endl;
    // }

    // {
    //     //p45
    //     int x;
    //     std::cout << x << std::endl;//仅仅会警告x可能会初始化，打印结果是不定的值
    // }

    {
        //p50 reference
        int ival = 10;
        int &refVal = ival;
        // int &refVal2;//必须初始化对类型 int 的引用
        int &refVal3 = refVal;
    } {
        //p51引用类型和对应的对象类型必须匹配
        // int &refVal4 = 10; // error: initializer must be an object
        double dval = 3.14;
        // int &refVal5 = dval; // error: initializer must be an int object
        int ival = 10;
        // double &refVal = ival;
    } {
        // p52 指针类型的匹配性
        double dval;
        double *pd = &dval; // ok: initializer is the address of a double
        double *pd2 = pd; // ok: initializer is a pointer to double
        // int *pi = pd; // error: types of pi and pd differ
        // pi = &dval; // error: assigning the address of a double to a pointer to int
    } {
        int i = 42;
        int *p; // p is a pointer to int
        int *&r = p; // r is a reference to the pointer p
        r = &i; // r refers to a pointer; assigning &i to r makes p point to i
        *r = 0; // dereferencing r yields i, the object to which p points; changes i to 0
    } {
        // p58 如何引用一个指针
        int i = 42;
        int *p; // p is a pointer to int
        int *&r = p; // r is a reference to the pointer p
        r = &i; // r refers to a pointer; assigning &i to r makes p point to i
        *r = 0; // dereferencing r yields i, the object to which p points; changes i to 0
    } {
        // p59 const变量必须初始化，初始化可以在编译阶段也可以在运行阶段
        auto get_size = []() {return 1;};
        const int i = get_size(); // ok: initialized at run time
        const int j = 42; // ok: initialized at compile time
        // const int k; // error: k is uninitialized const
    }
    {
        //p60 测试const不会重定义的情况
        //下面两个const int并非相同的变量
        //测试 1 const local to file，两者的地址不同
        // std::cout << getBufSizeAddr() << std::endl;
        // std::cout << &bufSize << std::endl;

        //测试 2 两者的地址是一样的
        // std::cout << getBufSizeAddr() << std::endl;
        // std::cout << &bufSize << std::endl;

        //测试 3 不能直接在.h文件中定义extern const int = xxx;
        //这里会忽略extern，同时也不会在每个文件中独立的生成一个const，
        //只会直接报错multiple definition
        // std::cout << getBufSizeAddr() << std::endl;
        // std::cout << &bufSize << std::endl;

        //测试 4
        std::cout << getBufSizeAddr() << std::endl;
        std::cout << &bufSize << std::endl;
    }

    {
        // p61 const的引用可以绑定更加多情况的值，比如说相同类型的字面量，表达式，非const类型的变量
        int i = 42;
        const int &r1 = i; // we can bind a const int& to a plain int object
        const int &r2 = 42; // ok: r1 is a reference to const
        const int &r3 = r1 * 2; // ok: r3 is a reference to const
        // int &r4 = r1 * 2; // error: r4 is a plain, non const reference
    }
    {
        // p61 const引用可以绑定到可以转换的类型，但是非const引用不可以，书中解释了为何C++不让后者可以通过编译
        double dval = 3.14;
        const int &r1 = dval;
        int i = 1;
        const double &r2 = i;
    }
}


TEST(ch2, exercise0203) {
    unsigned u = 10, u2 = 42;
    std::cout << u2 - u << std::endl; //32
    std::cout << u - u2 << std::endl; //4,294,967,264 = 2^32 - 42 + 10
    int i = 10, i2 = 42;
    std::cout << i2 - i << std::endl; //32
    std::cout << i - i2 << std::endl; //-32
    std::cout << i - u << std::endl; //0
    std::cout << u - i << std::endl; //0
}

TEST(ch2, fewf) {
}

TEST(ch2, test02exercise0209) {
    // int i = { 3.14 }; //收缩变换
    // double salary = wage = 999.99;
}

std::string global_str;
int global_int;
TEST(ch2, test03exercise0210) {
    int local_int;
    std::string local_str;
}

TEST(ch2, exercise0212) {
    // int double = 3.14;
    // int _ = 1;
    // std::cout << _ << std::endl;
    // int catch-22;
    double Double = 3.14;
}

TEST(ch2, exercise0220) {
    int i = 42;
    int *p1 = &i;
    *p1 = *p1 * *p1; //这种写法是不会报错的
    std::cout << *p1 << std::endl;
}

TEST(ch2, exercise0221) {
    int i = 0;
    // double *dp = &i;
    // int *ip = i;
    int *p1 = &i;
}

TEST(ch2, exercise0222) {
    int i = 1;
    // int i = 0;
    int *p = &i;
    if (*p) {
        std::cout << *p << std::endl;
    }
}

TEST(ch2, test04auto) {
    auto i = 0, *p = &i;
    // auto sz = 0, pi = 3.14;
    auto a = i;

    const int ci = i, &cr = ci;
    auto b = ci; // b is an int (top-level const in ci is dropped)
    auto c = cr; // c is an int (cr is an alias for ci whose const is top-level)
    auto d = &i; // d is an int*(& of an int object is int*)
    auto e = &ci; // e is const int*(& of a const object is low-level const)
    const auto f = ci;

    auto &g = ci; // g is a const int& that is bound to ci
    // auto &h = 42; // error: we can't bind a plain reference to a literal
    const auto &j = 42; // ok: we can bind a const reference to a literal

    {
        const int i = 42;
        auto j = i;
        const auto &k = i;
        auto *p = &i;
        const auto j2 = i, &k2 = i;
    }
}

TEST(ch2, test05decltype) {
    const int ci = 0, &cj = ci;
    decltype(ci) x = 0; // x has type const int
    decltype(cj) y = x; // y has type const int& and is bound to x
    decltype(cj) z = 1; // error: z is a reference and must be initialized
    {
        // decltype of an expression can be a reference type
        int i = 42, *p = &i, &r = i;
        decltype(r + 0) b; // ok: addition yields an int; b is an (uninitialized) int
        // decltype(*p) c; // error: c is int& and must be initialized
    } {
        int i = 0;
        // decltype of a parenthesized variable is always a reference
        // decltype((i)) d; // error: d is int& and must be initialized
        decltype(i) e; // ok: e is an (uninitialized) int
    }
}
